#pragma once

#include <string>
using namespace std;

#include "talk/base/helpers.h"
#include "talk/base/thread.h"
#include "talk/base/sigslot.h"
#include "talk/base/ssladapter.h"
#include "talk/base/criticalsection.h"

#include "talk/xmpp/jid.h"
#include "talk/xmpp/xmppclientsettings.h"

#include "talk/examples/login/xmppthread.h"
#include "talk/examples/login/xmppauth.h"
#include "talk/examples/login/xmpppump.h"
#include "talk/examples/login/xmppsocket.h"

#include "talk/examples/crossfirewall/cmdconsole.h"
#include "talk/examples/crossfirewall/xmltask/status.h"

#include "talk/examples/crossfirewall/xmltask/jingleinfotask.h"
#include "talk/examples/crossfirewall/xmltask/presenceouttask.h"
#include "talk/examples/crossfirewall/xmltask/presencepushtask.h"
#include "talk/examples/crossfirewall/xmltask/xmlsendertask.h"
#include "talk/examples/crossfirewall/xmltask/HeartBeatThread.h"

using namespace talk_base;

#define  HTTPALLOCATOR

#define  LOGIN_BOMB_TIME_OUT		(60*1000)
#define	 PING_INTERVAL				(60*1000)

#define  LOGIN_MAX_RETRYS           10
#define  LOGIN_RETRY_DELAY          3000

#define  CMD_LOGIN_STATE_CHANGE		100
#define  CMD_LOGIN_ROSTER_CHANGE	101
#define  CMD_LOGIN_BOMB_TIMEOUT		102
#define  CMD_LOGIN_DO_PING			103
#define  CMD_XMPP_FLUSH				104
#define  CMD_LOGIN_INIT_CORE		105
#define  CMD_LOGIN_UNINIT_CORE		106


namespace cricket {

	struct CFUsrInfo {
		string usrname;
		string usrpass;
		string resource;
		string computername;
		int logintype;
	};

	struct LoginState : public MessageData {
		buzz::XmppEngine::State state_;
		buzz::XmppEngine::Error error_;
		LoginState(buzz::XmppEngine::State state, buzz::XmppEngine::Error error) : state_(state), error_(error) { }
	};

	struct RosterItem : public MessageData {
		std::string jid_;
		std::string status_;
		std::string version_;
		buzz::Status::Show show_;	

		RosterItem(std::string jid) : jid_(jid) {}
		RosterItem(std::string jid, std::string status, std::string version, buzz::Status::Show show) 
			: jid_(jid), status_(status), version_(version), show_(show) { }
	};

	class CFLogin: public CoreCmd, public sigslot::has_slots<> 
	{
	public:
		CFLogin() {}
		~CFLogin() {}

		bool Login(const CFUsrInfo& usrinfo);
		bool Logout();

		void LoginStart();
		bool LoginRetry();

		buzz::XmppClient* GetXmppClient() { return xmpp_client_; }
		const buzz::Jid& GetJid() { return xmpp_client_->jid(); }
		Thread* GetLoginThread() { return login_thread_; }
		void SetCmdWayToCore(talk_base::Thread* thread, CmdConsole* console) { cmd_thread_ = thread;  cmd_console_ = console; }

		bool Ping();
		void FlushXmpp()   { login_thread_->Post(cmd_console_, CMD_XMPP_FLUSH); }	
		void OnFlushXmpp() { xmpp_pump_->RunTasks(); }

		void SetLoginBombEnabled(bool enable) { talk_base::CritScope cc(&loginstate_crit_);  login_bomb_ = enable; }
		bool GetLoginBombEnabled() { talk_base::CritScope cc(&loginstate_crit_);  return login_bomb_; }
		void CancelLoginBomb() { this->SetLoginBombEnabled(false); }
		void BombLoginBomb() {
			if(GetLoginBombEnabled()){
				cmd_thread_->Post(cmd_console_, CMD_LOGIN_STATE_CHANGE, 
					new LoginState(buzz::XmppEngine::STATE_OPEN, buzz::XmppEngine::ERROR_CONNECTION_CLOSED));
			}
		}

		void OnJingleInfo(const std::string & relay_token, const std::vector<std::string> &relay_addresses, const std::vector<talk_base::SocketAddress> &stun_addresses);
		void OnOFInfo( const std::string &publicIP, const std::vector<talk_base::SocketAddress> &tcpStuns);
		
	private:
		bool CheckLoginState();
		bool CheckJidValid(const CFUsrInfo& usrinfo);
		void InitLoginParameter();

		void OnLoginStateChange(buzz::XmppEngine::State state);
		void OnPresenceStatusUpdate(const buzz::Status& status);

		void InitLoginTask();
		void InitUsrStatusTask();
		//void InitDevStatusTask();
		
		void PingStart();
		void PingStop();

	public:
		sigslot::signal3<const std::string &, const std::vector<std::string> &, const std::vector<talk_base::SocketAddress> &> SignalJingleInfo;
		sigslot::signal2<const std::string &, const std::vector<talk_base::SocketAddress> &> SignalOFInfo;

	private:
		bool                      login_bomb_;
		int                       login_state_;
		int                       login_retrys_;

		buzz::XmppClientSettings  login_xcs_;
		buzz::Jid                 login_jid_;
		CFUsrInfo                 login_usrinfo_;

		XmppPump*                 xmpp_pump_;
		XmppSocket*               xmpp_socket_;
		buzz::XmppClient*         xmpp_client_;

		CriticalSection           login_crit_;
		CriticalSection           logout_crit_;
		CriticalSection           loginstate_crit_;

		Thread*                   login_thread_;
		Thread*                   cmd_thread_;
		CmdConsole*               cmd_console_;

#ifdef WIN32
		HANDLE                    login_tid_;	
#else
		pthread_t                 login_tid_;
#endif

		buzz::Status      status_usr_;
		HeartBeatManager  mgr_ping_;

		buzz::JingleInfoTask*       jingle_info_task_;
		buzz::PresencePushTask*     presence_push_task_;
		buzz::PresenceOutTask*      presence_out_task_;
	};
}